#! /bin/python

'''
Created on 2011-2-5
This script parse the input line from stdin as shell commands and 
dump all stdout/stderr output into a log file.
Usage: kuaicmd.py output.log
@author: madlee
'''

from threading import Thread, Lock
from os import remove
from os.path import exists, abspath, isfile
from datetime import datetime
from time import sleep
from shlex import split
import subprocess

CHECK_INTERVAL = 1.0
SIG_KILL = '.kill'
COMMANDS = {}
killed = False
lock = Lock()


def dump_output(output, line):
    global lock
    lock.acquire()
    output.write(line.rstrip()+'\n')
    lock.release()
            

class DumpJobOutput(Thread):
    def __init__(self, tag, input, output):
        Thread.__init__(self)
        self.tag = tag
        self.input = input
        self.output = output

    def run(self):
        global lock
        line = self.input.readline()
        while line:
            dump_output(self.output, self.tag+line)
            line = self.input.readline()

class CheckKillSignal(Thread):
    def __init__(self, process, sig_kill):
        Thread.__init__(self)
        self.process = process
        self.sig_kill = sig_kill
        
    def run(self):
        global killed
        while self.process.poll() is None:
            if exists(self.sig_kill):
                self.process.terminate()
                try:
                    remove(self.sig_kill)
                except:
                    pass
                killed = True
                break
            else:
                sleep(CHECK_INTERVAL)

if __name__ == '__main__':
    from sys import argv, stdin
    if len(argv) != 2:
        print __doc__
    else:
        from subprocess import Popen, PIPE
        time1 = datetime.today()
        output = open(argv[1], 'wt')
        output.write('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n')
        output.write('>>>>    Job started at ' + str(time1) + '\n\n')
        sig_kill = abspath(SIG_KILL)
        if isfile(sig_kill):
            remove(sig_kill)
        commands = []
        cmd = stdin.readline()
        while cmd:
            cmd = split(cmd)
            for j in range(len(cmd)):
                if cmd[j] in COMMANDS:
                    cmd[j] = COMMANDS[cmd[j]]
            cmd = ' '.join(cmd)    
            commands.append(cmd)
            cmd = stdin.readline()
        
        kwargs = {}
        if subprocess.mswindows:
            su = subprocess.STARTUPINFO()
            su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            su.wShowWindow = subprocess.SW_HIDE
            kwargs['startupinfo'] = su

        for cmd in commands:
            dump_output(output, '>>  ' + cmd)
            process = Popen(cmd, 1, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE, **kwargs)
            dumpSTDOUT = DumpJobOutput('O>  ', process.stdout, output)
            dumpSTDOUT.start()
            dumpSTDERR = DumpJobOutput('E>  ', process.stderr, output)
            dumpSTDERR.start()
            timer = CheckKillSignal(process, sig_kill)
            timer.start()
            process.stdin.close()
            dumpSTDOUT.join()
            dumpSTDERR.join()
            if killed:
                break
            else:
                output.write('>>  Exit code: ' + str(process.poll()) + '\n\n\n\n')
            
        time2 = datetime.today()
        if killed:
            output.write('\n\n\n\n\n>>>>    Job killed by user at ' + str(time2))
        else:
            output.write('\n>>>>    Job finished at ' + str(time2))
        output.write('\n>>>>    Job costed ' + str(time2-time1) + '\n')
        output.write('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n')
        output.close()

